#include <stdio.h>
#include <sys/un.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include <client_unit.h>
#include <decode_unit.h>
#include <memcheck.h>
#include <log.h>
#include <http_decoder.h>

#include <sys/types.h>
#include <iomanip>
#include <fstream>
#include <ctime>
#include <iostream>
#include "dll.h"

#define MAX_ERR_RSP_MSG_LEN 4096

HTTP_SVR_NS_BEGIN


void HexDumpImp2(const void *pdata, unsigned int len, int num)
{
       if(pdata == 0 || len == 0)
        {
                 cout<<"error num" << num << "\n";
                return;
        }
    
        int cnt = 0;
        int n = 0;
        int cnt2 = 0;
        const char *data = (const char *)pdata;
        cout<<"Address               Hexadecimal values                  Printable\n";
        cout<<"-------  -----------------------------------------------  -------------\n";
        cout<<"num:[" << num << "]";
        cout << "\n";
        unsigned char buffer[20];
        unsigned int rpos = 0;

        while ( 1 )
        {
                if(len <= rpos)
                {
                        break;
                }
                if(len >= rpos + 16)
                {
                        memcpy(buffer, data + rpos, 16);
                        rpos += 16;
                        cnt = 16;
                }
                else
                {
                        memcpy(buffer, data + rpos, len - rpos);
                        cnt = len - rpos;
                        rpos = len;
                }
                if(cnt <= 0)
                {
                        return;
                }

                cout << setw(7) << ( int ) rpos << "  ";

                cnt2 = 0;
                for ( n = 0; n < 16; n++ )
                {
                        cnt2 = cnt2 + 1;
                        if ( cnt2 <= cnt )
                        {
                                cout << hex << setw(2) << setfill ( '0' ) <<  (unsigned int)buffer[n];
                        }
                        else
                        {
                                cout << "  ";
                        }
                        cout << " ";
                }

                cout << setfill ( ' ' );

                cout << " ";
                cnt2 = 0;
                for ( n = 0; n < 16; n++ )
                {
                        cnt2 = cnt2 + 1;
                        if ( cnt2 <= cnt )
                        {
                                if ( buffer[n] < 32 || 126 < buffer[n] )
                                {
                                        cout << '.';
                                }
                                else
                                {
                                        cout << buffer[n];
                                }
                        }
                }
                cout << "\n";
                cout << dec;
        }

        return;
}

CClientUnit::CClientUnit(CDecoderUnit* decoderunit, THttpStateInfo* httpinfo)   : 
CPollerObject (decoderunit->pollerunit(), httpinfo->_fd),
_stage (CONN_IDLE),
_decoder (CHttpDecoder::Instance()),
_owner (decoderunit),
_httpinfo (httpinfo),
_accesstimes (0),
_rspList(NULL),
_rspLastItem(NULL)
{
    
}

CClientUnit::~CClientUnit (void)
{
    while(NULL != _rspList)
    {
        TRspList* pItem = NULL;
        pItem = _rspList->_next;
        
        FREE_CLEAR(_rspList->_buffer);
        DELETE(_rspList);

        _rspList = pItem;
    }
}

int CClientUnit::Attach (void)
{
    if (NULL == _decoder)
    {
        log_error ("netfd[%d], stage[%d], msg[%s] CHttpDecoder instance is invalid.", netfd, _stage, strerror(errno));
        
        return -1;
    }
    
    EnableInput ();
    
    if (AttachPoller() == -1)
    {
        log_error ("invoke CPollerObject::AttachPoller() failed.");
        
        return -1;
    }

    _stage = CONN_IDLE;

    return 0;
}

//server peer
int CClientUnit::recv (void)
{    
    int ret = _decoder->decode_req_info (_httpinfo);

    switch (ret)
    {
        case DECODE_FATAL_ERROR:
            DisableInput ();
            log_warning ("decode fatal error netfd[%d] stage[%d] msg[%s]", netfd, _stage, strerror(errno));
            _stage = CONN_FATAL_ERROR;
            return -1;

        case DECODE_DATA_ERROR:
            DisableInput ();
            log_warning ("decode error, netfd[%d] stage[%d] msg[%s]", netfd, _stage, strerror(errno));
            _stage = CONN_DATA_ERROR;
            break;

        case DECODE_NO_FOUND_URL:
            DisableInput ();            
            _stage = CONN_DATA_ERROR;
            log_warning ("decode error, cgi no found, netfd[%d] stage[%d] msg[%s]", netfd, _stage, strerror(errno));
            break;

        case DECODE_DONE:
//            DisableInput ();
            _stage = CONN_RECV_DONE;
            log_debug ("decode done, netfd[%d], stage[%d]", netfd, _stage);
            break;
            
        case DECODE_WAIT_HEAD:
        case DECODE_WAIT_CONTENT:
            _stage = CONN_DATA_RECVING;
            log_debug ("decode wait, netfd[%d], stage[%d]", netfd, _stage);
            break;        

        case DECODE_DISCONNECT_BY_USER:
            DisableInput ();
            log_notice ("disconnect by user, netfd[%d] stage[%d] msg[%s] ", netfd, _stage, strerror(errno));
            _stage = CONN_DISCONNECT;
            break;

        case DECODE_PROCESS:
            _stage = CONN_PROCESS;
            break;

        default:
            DisableInput ();
            log_warning ("decode fatal error netfd[%d] stage[%d] msg[%s]", netfd, _stage, strerror(errno));
            _stage = CONN_FATAL_ERROR;
            return -1;
            break;
    }
    
    return 0;
}

int CClientUnit::response (void)
{
    log_debug("*DEBUG in CClientUnit response");

    char * buff = NULL;
    int bufLen = 0;
    _owner->get_helper_rspBuff(&buff, bufLen);

    log_debug("*DEBUG in CClientUnit response bufLen:[%d]", bufLen);
    
    if (_httpinfo->_w.data_len() != 0)
    {
        int ret = ::send (netfd, _httpinfo->_w.data(), _httpinfo->_w.data_len(), 0);
        
        if(-1 == ret)
        {
            if(errno==EINTR || errno==EAGAIN || errno==EINPROGRESS)
            {
                EnableOutput ();
                ApplyEvents ();
                
                _httpinfo->_w.append(buff, bufLen);
                _owner->free_helper_buf();
//--                _httpinfo->free_web_buf ();
                return CONN_DATA_SENDING;
            }
            
            DisableInput ();
            DisableOutput ();
            _stage = CONN_FATAL_ERROR;
            return -1;
        }
        
        if((unsigned)ret == _httpinfo->_w.data_len())
        {
            _httpinfo->_w.skip(ret);                
        }
        else if ((unsigned)ret < _httpinfo->_w.data_len())
        {
            EnableOutput ();
            ApplyEvents ();
            
            _httpinfo->_w.skip(ret);
            _httpinfo->_w.append(buff, bufLen);
            _owner->free_helper_buf();
//--            _httpinfo->free_web_buf ();
            _stage = CONN_DATA_SENDING;
            return ret;
        }
    }


    if(bufLen == 0 || buff == NULL)
    {
        _stage = CONN_SEND_DONE;
        return 0;
    }
    int ret = ::send (netfd, buff, bufLen, 0);
    log_debug("*STEP: sending package to CGIHOST, unix fd[%d], total len[%d], total sent[%d], buffer[%s]", bufLen, ret, ret, buff);
    
    if(-1 == ret)
    {
            if(errno==EINTR || errno==EAGAIN || errno==EINPROGRESS)
            {
                    EnableOutput ();
                    ApplyEvents ();
                    _httpinfo->_w.append(buff, bufLen);
                    _owner->free_helper_buf();

//--                    _httpinfo->free_web_buf ();
                    return CONN_DATA_SENDING;
            }
            
            DisableInput ();
            DisableOutput ();
            
            _stage = CONN_FATAL_ERROR;
    
            return -1;
    }
    
    if(ret == bufLen)
    {
            DisableOutput ();
            _owner->free_helper_buf();
            _stage = CONN_SEND_DONE;
            return ret;
    }
    
    if (ret < bufLen)
    {
            EnableOutput ();
            ApplyEvents ();
            _httpinfo->_w.append(buff+ret , bufLen-ret);
            _owner->free_helper_buf();
            _stage = CONN_DATA_SENDING;
    
            return ret;
    }
    DisableInput ();
    DisableOutput ();
    _stage = CONN_FATAL_ERROR;
    return -1;

}

int CClientUnit::add_rsp_buffer(char* buffer, int len, int type)
{
    log_debug("*STEP: add package to response list, package len [%d], type[%d]", len, type);
    
    TRspList* pItem = NULL;
    NEW(TRspList, pItem);
    if(NULL == pItem)
    {
        log_error("create TRspList object failed");
        return -1;
    }
    
    pItem->_buffer  = buffer;
    pItem->_len     = len;
    pItem->_sent    = 0;
    pItem->_type    = type;
    pItem->_next    = NULL;

    if(NULL != _rspLastItem)
        _rspLastItem->_next = pItem;
    else
        _rspList = pItem;

    _rspLastItem = pItem;

    return this->response();
}

int CClientUnit::InputNotify (void)
{
    this->recv();
    
    return _owner->web_input ();
}

int CClientUnit::OutputNotify (void)
{
    return _owner->web_output ();
}

int CClientUnit::HangupNotify (void)
{
    log_notice("*STEP: web connection is hangup, netfd[%d] stage[%d]", netfd, _stage);
    return _owner->web_hangup ();
}



HTTP_SVR_NS_END
